package com.mrd.util;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.hibernate.annotations.ManyToAny;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.core.JdbcTemplate;

import com.mrd.exception.validation.MRDValidationException;
import com.mrd.framework.utils.SpringUtils;
import com.mrd.gtimp.business.entity.Commodity;
import com.mrd.gtimp.business.entity.Declaration;
import com.mrd.gtimp.business.entity.GoodsCode;
import com.mrd.gtimp.order.entity.DeclaContainer;

/**
 * 校验类 Created by dengdc on 2016/10/24.
 */
public class GtimpBusinessUtil {

  private static final Logger logger = LoggerFactory.getLogger(GtimpBusinessUtil.class);

  /**
   * 检查报关单
   */
  public static void checkDeclaration(Declaration declaration) throws MRDValidationException {
    if(declaration == null){
      return;
    }
    StringBuilder error = new StringBuilder();
    StringUtils.userReflectToTrimString(declaration); // 去除字符串前后空格
    handleNullValueCustomJPAField(declaration); // 处理一些Null值
    try {
      GtimpBusinessUtil.checkContainers(declaration); // 检查集装箱
    } catch (MRDValidationException e) {
      error.append(e.getMessage()).append(",");
    }
    try {
      ValidationUtil.Groups group =
          "I".equals(declaration.getDeclaration_type()) ? ValidationUtil.Groups.in
              : ValidationUtil.Groups.out;
      //// TODO: 2017/2/7
      // ValidationUtil.validateByGroup(declaration, group); //检查进出口必填项
    } catch (MRDValidationException e) {
      error.append(e.getMessage()).append(",");
    }
    try {
      ValidationUtil.validate(declaration); // 检查字符长度
    } catch (MRDValidationException e) {
      error.append(e.getMessage()).append(",");
    }
    try {
      checkCommodityValidity(declaration);
    } catch (MRDValidationException e) {
      error.append(e.getMessage()).append(",");
    }
    if (error.length() > 0) {
      error.deleteCharAt(error.length() - 1);
      throw new MRDValidationException(error.toString());
    }
  }

  /**
   * 检查报关单集装箱的柜号、柜型
   *
   * @param declaration 报关单
   */
  public static void checkContainers(Declaration declaration) throws MRDValidationException {
    List<DeclaContainer> containerList = declaration.getDeclaContainers();
    if (containerList == null) {
      return;
    }
    StringBuilder error = new StringBuilder();

    for (DeclaContainer declaContainer : containerList) {
      try {
        declaContainer.setContainerNo(checkContainerNo(declaContainer.getContainerNo()));
      } catch (MRDValidationException e) {
        error.append(e.getMessage()).append(",");
      }
      try {
        declaContainer
            .setContainerStandard(checkContainerStandard(declaContainer.getContainerStandard()));
      } catch (MRDValidationException e) {
        error.append(declaContainer.getContainerNo()).append(e.getMessage()).append(",");
      }
    }
    if (error.length() > 0) {
      error.deleteCharAt(error.length() - 1);
      throw new MRDValidationException(error.toString());
    }
  }

  /**
   * 检查集装箱号
   *
   * @param containerNo 柜号
   * @return 符合规则的柜号
   */
  public static String checkContainerNo(String containerNo) throws MRDValidationException {
    if (org.apache.commons.lang3.StringUtils.isEmpty(containerNo)) {
      throw new MRDValidationException("空的集装箱号[不符合柜号命名规则]");
    }
    Pattern pattern = Pattern.compile("^[a-zA-Z]{4}\\d{7}$");
    Matcher matcher = pattern.matcher(containerNo);
    if (matcher.find()) {
      return matcher.group().toUpperCase();
    } else {
      throw new MRDValidationException("集装箱号#" + containerNo + "#[不符合柜号命名规则]");
    }
  }

  /**
   * 检查柜重
   *
   * @param containerStandard 柜型
   * @return 符合规则的柜号
   */
  public static String checkContainerStandard(String containerStandard)
      throws MRDValidationException {
    if (StringUtils.isEmpty(containerStandard)) {
      return containerStandard;
    }
    Pattern pattern = Pattern.compile("^[sSlL]$");
    Matcher matcher = pattern.matcher(containerStandard);
    if (matcher.find()) {
      return matcher.group().toUpperCase();
    } else {
      throw new MRDValidationException("柜型[柜型异常]");
    }
  }

  /**
   * 处理JPA 非基本类型及其包装类、非Date的自定义类型的Null字段
   */
  public static void handleNullValueCustomJPAField(Object t) throws MRDValidationException {
    if (t == null) {
      return;
    }
    Class tClass = t.getClass();
    List<Field> fields = FieldUtils.getAllFieldsList(tClass);
    for (Field field : fields) {
      if (isJPACustomField(field)) {
        PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(tClass, field.getName());
        if (pd == null) {
          logger.warn(field + "没有get/set方法");
          continue;
        }
        Method readMethod = pd.getReadMethod();
        Method writeMethod = pd.getWriteMethod();
        try {
          Object val = readMethod.invoke(t);
          if (val == null) {
            if (field.getType().isAssignableFrom(List.class)) {
              writeMethod.invoke(t, new ArrayList<>());
            } else if (field.getType().isAssignableFrom(Set.class)) {
              writeMethod.invoke(t, new HashSet<>());
            } else if (field.getType().isAssignableFrom(Object[].class)) {
              writeMethod.invoke(t, new Object[] {});
            } else if (field.getType().isAssignableFrom(Map.class)) {
            } else if (field.getType().isAssignableFrom(Date.class)) {
            } else {
              writeMethod.invoke(t, field.getType().newInstance());
            }
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
  }

  /**
   * 判断是否是JPA自定义类型对象
   *
   * @param field 字段
   */
  private static boolean isJPACustomField(Field field) {
    Annotation[] annotations = field.getDeclaredAnnotations();
    Class[] jpaAnnotations = new Class[] {OneToMany.class, ManyToMany.class, ManyToAny.class};
    if (annotations.length > 0) {
      for (Annotation annotation : annotations) {
        for (Class jpaAnnotation : jpaAnnotations) {
          if (jpaAnnotation.equals(annotation.annotationType())) {
            return true;
          }
        }
      }
    }
    return false;
  }

  /**
   * 将3.0柜列表转成2.0数据
   *
   * @param declaration 报关单数据
   */
  public static void formatContainerListAsContainerNoAndContainerNoShow(Declaration declaration) {
    List<DeclaContainer> containerList = declaration.getDeclaContainers();
    if (CollectionUtils.isEmpty(containerList)) {
      return;
    }
    String containerJsonFormat = "{\"CONTAINER_NO\":\"%s\",\"CT_SIZE\":\"%s\"}";
    List<String> containerJsonList = new ArrayList<>();
    List<String> containerNoList = new ArrayList<>();
    for (DeclaContainer container : containerList) {
      containerNoList.add(container.getContainerNo());
      containerJsonList.add(String.format(containerJsonFormat, container.getContainerNo(),
          container.getContainerStandard()));
    }
    declaration.setContainer_no(StringUtils.join(containerNoList.iterator(), ","));
    declaration.setContainer_no_show(
        String.format("[%s]", StringUtils.join(containerJsonList.iterator(), ",")));
  }

  public static void checkCommodityValidity(Declaration declaration) throws MRDValidationException {
    List<Commodity> commoditys = declaration.getCommodities();
    String errorMsg = "";
    if (CollectionUtils.isEmpty(commoditys)) {
      errorMsg += "没有商品项！";
      throw new MRDValidationException(errorMsg);
    }
    JdbcTemplate jdbcTemplate = SpringUtils.getBean(JdbcTemplate.class);
    StringBuilder sql = new StringBuilder(
        "select t.code_t,t.code_s,t.unit_1,t.unit_2  from CDAMS_QP_GOODS_CODE t where 1 = 2 ");
    String expressionFormat = "or (t.code_t = %s and t.code_s = %s)";
    for (Commodity commo : commoditys) {
      sql.append(String.format(expressionFormat, commo.getCode_t(), commo.getCode_s()));
    }

    List<GoodsCode> goodsCodes = jdbcTemplate.query(sql.toString(), (rs, rowNum) -> {
      GoodsCode goodsCode = new GoodsCode();
      goodsCode.setCODE_T(rs.getString(1));
      goodsCode.setCODE_S(rs.getString(2));
      goodsCode.setUNIT_1(rs.getString(3));
      goodsCode.setUNIT_2(rs.getString(4));
      return goodsCode;
    });

    if (CollectionUtils.isEmpty(goodsCodes)) {
      errorMsg += "没有找到对应海关商品项！";
      throw new MRDValidationException(errorMsg);
    }

    out: for (Commodity commodity : commoditys) {
      String commoLegalUnitCode = commodity.getLegalUnitCode();
      String commoSecondUnitCode = commodity.getSecondUnitCode();
      for (GoodsCode goodsCode : goodsCodes) {
        String goodsCodeUnit1 = goodsCode.getUNIT_1();
        String goodsCodeUnit2 = goodsCode.getUNIT_2();
        if (commodity.getCode_t().equals(goodsCode.getCODE_T())
            && commodity.getCode_s().equals(goodsCode.getCODE_S())) {
          if (!commoLegalUnitCode.equals(goodsCodeUnit1)) {
            errorMsg +=
                "商品项目【" + commodity.getName() + "|" + commodity.getCode_t() + commodity.getCode_s()
                    + "】法定单位有误,<label style='color:red'>请重新选择商品以获取最新的要求</label><br/>";
          }
          if ((org.apache.commons.lang3.StringUtils.isNotEmpty(commoSecondUnitCode)
              && !commoSecondUnitCode.equals(goodsCodeUnit2))
              || (org.apache.commons.lang3.StringUtils.isEmpty(commoSecondUnitCode)
                  && org.apache.commons.lang3.StringUtils.isNotEmpty(goodsCodeUnit2))) {
            errorMsg +=
                "商品项目【" + commodity.getName() + "|" + commodity.getCode_t() + commodity.getCode_s()
                    + "】第二计量单位有误,<label style='color:red'>请重新选择商品以获取最新的要求</label><br/>";
          }
          commodity.setLegalUnitCode(goodsCodeUnit1);
          commodity.setSecondUnitCode(goodsCodeUnit2);
          if (org.apache.commons.lang3.StringUtils.isEmpty(goodsCodeUnit2)) {
            commodity.setSecond_count(null);
            commodity.setSecond_unit(null);
          }
          continue out;
        }
      }
      errorMsg += "商品项（" + commodity.getCode_t() + commodity.getCode_s() + "）在代码库中不存在<br/>";
    }
    if (org.apache.commons.lang3.StringUtils.isNotEmpty(errorMsg)) {
      throw new MRDValidationException(errorMsg);
    }
  }
}
